﻿using System.Linq;
using System.Web.Mvc;
using Orchard;
using Orchard.ContentManagement;
using Orchard.Localization;
using Orchard.UI.Admin;
using Orchard.UI.Notify;
using Contrib.Chapters.Services;
using Contrib.Chapters.Models;
using Contrib.Chapters.ViewModels;

namespace Contrib.Chapters.Controllers {
    
    [ValidateInput(false)]
    [Admin]
    public class ChapterAdminController : Controller, IUpdateModel {
        private readonly IChapterService _chapterService;

        public ChapterAdminController(IOrchardServices services, IChapterService chapterService) {
            Services = services;
            _chapterService = chapterService;
            T = NullLocalizer.Instance;
        }

        public IOrchardServices Services { get; set; }
        
        public Localizer T { get; set; }

        public ActionResult Index(int bookId) {
            var book = _chapterService.GetBook(bookId);
            if(book == null) {
                return HttpNotFound();
            }

            var chapters = _chapterService.GetChapters(book);
            var model = Services.New.Model(Chapters: chapters, Book: book);
            return View((object)model);
        }

        public ActionResult SelectChapter(int bookId) {
            if (!Services.Authorizer.Authorize(Permissions.ManageChapters, T("Not allowed to create chapters")))
                return new HttpUnauthorizedResult();

            var book = _chapterService.GetBook(bookId);
            if(book == null) {
                return HttpNotFound();
            }

            var chapters = _chapterService.GetChapters(book);

            if (chapters.Any()) {
                var model = new SelectChapterViewModel() {
                    Chapters = chapters,
                    SelectedChapterId = -1
                };

                return View(model);
            }

            return RedirectToAction("Create", new { bookId, parentChapterId = -1 });
        }

        [HttpPost]
        public ActionResult SelectChapter(int bookId, int selectedChapterId) {
            if (!Services.Authorizer.Authorize(Permissions.ManageChapters, T("Not allowed to select chapters")))
                return new HttpUnauthorizedResult();

            return RedirectToAction("Create", new { bookId, parentChapterId = selectedChapterId});
        }

        public ActionResult Create(int bookId, int parentChapterId)
        {
            if (!Services.Authorizer.Authorize(Permissions.ManageChapters, T("Not allowed to create chapters")))
                return new HttpUnauthorizedResult();

            var book = _chapterService.GetBook(bookId);
            var parentChapter = _chapterService.GetChapter(parentChapterId);
            var chapter = _chapterService.NewChapter(book);

            // assign a container to show the full route while editing
            chapter.Container = parentChapter == null ? (IContent)book : (IContent)parentChapter;

            var model = Services.ContentManager.BuildEditor(chapter);
            return View((object)model);
        }

        [HttpPost, ActionName("Create")]
        public ActionResult CreatePOST(int bookId, int parentChapterId)
        {
            if (!Services.Authorizer.Authorize(Permissions.ManageChapters, T("Couldn't create chapter")))
                return new HttpUnauthorizedResult();

            var book = _chapterService.GetBook(bookId);
            var parentChapter = _chapterService.GetChapter(parentChapterId);

            var chapter = _chapterService.NewChapter(book);
            chapter.Container = parentChapter == null ? book.ContentItem : parentChapter.ContentItem;

            var model = Services.ContentManager.UpdateEditor(chapter, this);

            if (!ModelState.IsValid) {
                Services.TransactionManager.Cancel();
                return View(model);
            }

            Services.ContentManager.Create(chapter, VersionOptions.Published);

            Services.Notifier.Information(T("The {0} chapter has been created.", chapter.Title));

            return RedirectToAction("Index", new { bookId });
        }

        public ActionResult Edit(int id)
        {
            if (!Services.Authorizer.Authorize(Permissions.ManageChapters, T("Couldn't edit chapter")))
                return new HttpUnauthorizedResult();

            var chapter = Services.ContentManager.Get<ChapterPart>(id);

            if (chapter == null) {
                return HttpNotFound();
            }

            var model = Services.ContentManager.BuildEditor(chapter);

            return View((object)model);
        }

        [HttpPost, ActionName("Edit")]
        public ActionResult EditPOST(int id) {
            if (!Services.Authorizer.Authorize(Permissions.ManageChapters, T("Couldn't edit chapter")))
                return new HttpUnauthorizedResult();

            var chapter = Services.ContentManager.Get<ChapterPart>(id);
            var model = Services.ContentManager.UpdateEditor(chapter.ContentItem, this);

            if (!ModelState.IsValid) {
                Services.TransactionManager.Cancel();
                return View(model);
            }

            _chapterService.ChangeName(chapter, (string)model.Title);

            return RedirectToAction("Index", new { bookId = chapter.Record.Book.Id } );
        }

        public ActionResult EditChapters(int id) {
            if (!Services.Authorizer.Authorize(Permissions.ManageChapters, T("Couldn't edit chapters")))
                return new HttpUnauthorizedResult();

            var chapter = Services.ContentManager.Get<ChapterPart>(id);

            if (chapter == null) {
                return HttpNotFound();
            }

            var viewModel = Services.New.ViewModel()
                .ParentChapter(chapter)
                .Chapters(_chapterService.GetChildren(chapter));

            return View(viewModel);
        }

        public ActionResult Add(int parentId) {
            if (!Services.Authorizer.Authorize(Permissions.ManageChapters, T("Couldn't create a chapter")))
                return new HttpUnauthorizedResult();

            var parent = Services.ContentManager.Get<ChapterPart>(parentId);

            if (parent == null) {
                return HttpNotFound();
            }

            var chapter = Services.ContentManager.New<ChapterPart>(parent.ContentItem.ContentType);
            chapter.Container = parent;

            var model = Services.ContentManager.BuildEditor(chapter);
            return View("Create", (object)model);
        }

        [HttpPost, ActionName("Add")]
        public ActionResult AddPOST(int parentId) {
            if (!Services.Authorizer.Authorize(Permissions.ManageChapters, T("Couldn't create chapter")))
                return new HttpUnauthorizedResult();

            var parent = Services.ContentManager.Get<ChapterPart>(parentId);

            if (parent == null) {
                return HttpNotFound();
            }

            var chapter = Services.ContentManager.New<ChapterPart>(parent.ContentItem.ContentType);
            var model = Services.ContentManager.UpdateEditor(chapter.ContentItem, this);

            chapter.Position = _chapterService.GetDirectChildren(parent).Count() + 1;
            chapter.Container = parent;

            Services.ContentManager.Create(chapter, VersionOptions.Published);

            if (!ModelState.IsValid) {
                Services.TransactionManager.Cancel();
                return View(model);
            }

            var rootId = chapter.Record.Book != null
                ? chapter.Record.Book.Id
                : chapter.Id;

            return RedirectToAction("EditChapters", new { id = rootId } );
        }

        public ActionResult Delete(int id) {
            if (!Services.Authorizer.Authorize(Permissions.ManageChapters, T("Couldn't create chapter")))
                return new HttpUnauthorizedResult();

            var chapter = Services.ContentManager.Get<ChapterPart>(id);

            if (chapter == null) {
                return HttpNotFound();
            }

            bool redirectToChapter = chapter.Record.Book != null;

            _chapterService.Delete(chapter);

            Services.Notifier.Information(T("Chapter was successfully deleted"));

            if (redirectToChapter) {
                return RedirectToAction("EditChapters", new { id = chapter.Record.Book.Id });
            }
            
            return RedirectToAction("Index");            
        }

        public ActionResult MoveChapter(int bookId, int chapterId)
        {
            if (!Services.Authorizer.Authorize(Permissions.ManageChapters, T("Not allowed to move chapters")))
                return new HttpUnauthorizedResult();

            var chapter = _chapterService.GetChapter(chapterId);
            if (chapter == null) {
                return HttpNotFound();
            }

            var book = _chapterService.GetBook(bookId);
            if (book == null) {
                return HttpNotFound();
            }

            var model = new MoveChapterViewModel {
                Chapters = _chapterService.GetChapters(book).Where(t => !(t.Path + "/").StartsWith(chapter.Path + "/")),
                ChapterId = chapterId,
                SelectedChapterId = -1
            };

            return View(model);
        }

        [HttpPost]
        public ActionResult MoveChapter(int bookId, int selectedChapterId, int chapterId)
        {
            if (!Services.Authorizer.Authorize(Permissions.ManageChapters, T("Not allowed to move chapters")))
                return new HttpUnauthorizedResult();

            var book = _chapterService.GetBook(bookId);
            var parentChapter = _chapterService.GetChapter(selectedChapterId);
            var chapter = _chapterService.GetChapter(chapterId);

            _chapterService.MoveChapter(book, chapter, parentChapter);

            return RedirectToAction("Index", new { bookId });
        }

        bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) {
            return TryUpdateModel(model, prefix, includeProperties, excludeProperties);
        }

        void IUpdateModel.AddModelError(string key, LocalizedString errorMessage) {
            ModelState.AddModelError(key, errorMessage.ToString());
        }
    }
}
